﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace HF.Test
{
    class TestWrite
    {
        /// <summary>
        /// 取执行 1000000 次 <paramref name="action"/> 所耗毫秒
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        static long GetTick(Action action)
        {
            var t = Stopwatch.StartNew();
            for (int i = 0; i < 1000000; i++)
            {
                action();
            }
            t.Stop();
            var result = t.ElapsedMilliseconds;
            return result;
        }

        /// <summary>
        /// 写入对象属性
        /// </summary>
        public static long[] WriteClassProperty()
        {
            var pro = typeof(ClassObj).GetProperty(nameof(ClassObj.Name));
            HExpr.Property.Writer.Complice(typeof(ClassObj), pro.Name, out var action, out var fast);
            var fastWrite = fast as Action<ClassObj, string>;

            var obj = new ClassObj();
            var result = new long[]
            {
                GetTick(() => { obj.Name = "1"; }),
                GetTick(() => { fastWrite(obj,"2"); }),
                GetTick(() => { action(obj,"3"); }),
                GetTick(() => { pro.SetValue(obj, "4"); }),
            };
            return result;
        }

        /// <summary>
        /// 写结构体属性
        /// </summary>
        public static long[] WriteStructProperty()
        {
            var pro = typeof(StructObj).GetProperty(nameof(StructObj.Name));
            HExpr.Property.Writer.Complice(typeof(StructObj), pro.Name, out var action, out var fast);
            var fastWrite = fast as HExpr.ActionRef<StructObj, string>;
            object obj = new StructObj();
            var test = new StructObj();
            var result = new long[]
            {
                GetTick(() => { test.Name = "1"; }),
                GetTick(() => { fastWrite(ref test,"2"); }),
                GetTick(() => { action(obj,"3"); }),
                GetTick(() => { pro.SetValue(obj, "4"); }),
            };
            return result;
        }

        /// <summary>
        /// 写入类字段
        /// </summary>
        public static long[] WriteClassField()
        {
            var field = typeof(ClassObj).GetField(nameof(ClassObj.Address));
            HExpr.Property.Writer.Complice(typeof(ClassObj), field.Name, out var action, out var fast);
            var fastWrite = fast as Action<ClassObj, string>;

            var obj = new ClassObj();
            var result = new long[]
            {
                GetTick(() => { obj.Address = "1"; }),
                GetTick(() => { fastWrite(obj,"2"); }),
                GetTick(() => { action(obj,"3"); }),
                GetTick(() => { field.SetValue(obj, "4"); }),
            };
            return result;
        }

        /// <summary>
        /// 写入结构体字段
        /// </summary>
        public static long[] WriteStructField()
        {
            var field = typeof(StructObj).GetField(nameof(StructObj.Address));
            HExpr.Property.Writer.Complice(typeof(StructObj), field.Name, out var action, out var fast);
            var fastWrite = fast as HExpr.ActionRef<StructObj, string>;

            object obj = new StructObj();
            var test = new StructObj();
            var result = new long[]
            {
                GetTick(() => { test.Address = "1"; }),
                GetTick(() => { fastWrite(ref test,"2"); }),
                GetTick(() => { action(obj,"3"); }),
                GetTick(() => { field.SetValue(obj, "4"); }),
            };
            return result;
        }

        /// <summary>
        /// 写入类索引属性
        /// </summary>
        public static long[] WriteClassIndexProperty()
        {
            var paramTypes = new Type[] { typeof(int), typeof(string) };
            const BindingFlags C_BF = BindingFlags.Public | BindingFlags.Instance;
            var pro = typeof(ClassObj).GetProperties(C_BF)
                .FirstOrDefault(v => v.Name == "Item");
            HExpr.Property.Writer.Complice(typeof(ClassObj), paramTypes, out var action, out var fast);
            var fastWrite = fast as Action<ClassObj, int, string, int>;

            var obj = new ClassObj();
            var prm = new object[] { 1, "1" };
            var result = new long[]
            {
                GetTick(() => { obj[1,"1"] = 1; }),
                GetTick(() => { fastWrite(obj, 1, "1", 2); }),
                GetTick(() => { action(obj,prm,3); }),
                GetTick(() => { pro.SetValue(obj, 4, prm); }),
            };
            return result;
        }

        /// <summary>
        /// 写入类索引属性
        /// </summary>
        public static long[] WriteStructIndexProperty()
        {
            var paramTypes = new Type[] { typeof(int), typeof(string) };
            const BindingFlags C_BF = BindingFlags.Public | BindingFlags.Instance;
            var pro = typeof(StructObj).GetProperties(C_BF)
                .FirstOrDefault(v => v.Name == "Item");
            HExpr.Property.Writer.Complice(typeof(StructObj), paramTypes, out var action, out var fast);
            var fastWrite = fast as HExpr.ActionRef<StructObj, int, string, int>;

            object obj = new StructObj();
            var test = new StructObj();
            var prms = new object[] { 1, "1" };
            var result = new long[]
            {
                GetTick(() => { test[1, "1"] = 1; }),
                GetTick(() => { fastWrite(ref test, 1, "1", 2); }),
                GetTick(() => { action(obj, prms, 3); }),
                GetTick(() => { pro.SetValue(obj, 4, prms); }),
            };
            return result;
        }        
    }
}
